package com.autumn.security.realm;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import com.autumn.security.AutumnAccountCredentialsException;
import com.autumn.security.AutumnAccountStatusException;
import com.autumn.security.AutumnAuthenticationException;
import com.autumn.security.auth.AutumnAuthenticationToken;
import com.autumn.security.auth.UserNamePasswordToken;
import com.autumn.security.constants.UserStatusConstants;
import com.autumn.security.context.AutumnSecurityContextHolder;
import com.autumn.security.crypto.IAutumnPasswordProvider;
import com.autumn.security.user.IAutumnUser;
import com.autumn.security.user.IAutumnUserCredentialsService;
import com.autumn.util.StringUtils;

/**
 * 授权
 * 
 * @author 杨昌国 2018-12-06 02:04:39
 */
public class AutumnAuthorizingRealm extends AuthorizingRealm {

	/**
	 * 日志
	 */
	private static final Log logger = LogFactory.getLog(AutumnAuthorizingRealm.class);

	private final IAutumnPasswordProvider passwordProvider;

	private final IAutumnUserCredentialsService credentialsService;

	/**
	 * 
	 * @param passwordProvider
	 * @param credentialsService
	 */
	public AutumnAuthorizingRealm(IAutumnPasswordProvider passwordProvider,
			IAutumnUserCredentialsService credentialsService) {
		this.passwordProvider = passwordProvider;
		this.credentialsService = credentialsService;

	}

	public IAutumnPasswordProvider getPasswordProvider() {
		return passwordProvider;
	}

	public IAutumnUserCredentialsService getCredentialsService() {
		return credentialsService;
	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		IAutumnUser user = AutumnSecurityContextHolder.getAutumnUser();
		if (user == null) {
			return authorizationInfo;
		}
		List<String> roles = user.getRoles();
		if (roles != null) {
			for (String role : roles) {
				if (!StringUtils.isNullOrBlank(role)) {
					authorizationInfo.addRole(role);
				}
			}
		}
		List<String> permissions = user.getPermissions();
		if (permissions != null) {
			for (String permission : permissions) {
				if (!StringUtils.isNullOrBlank(permission)) {
					authorizationInfo.addStringPermission(permission);
				}
			}
		}
		return authorizationInfo;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		if (token instanceof AutumnAuthenticationToken) {
			AutumnAuthenticationToken authToken = (AutumnAuthenticationToken) token;
			IAutumnUser user = this.getCredentialsService().loadUserByToken(authToken);
			if (user == null) {
				throw new AutumnAccountCredentialsException("无效的用户认证。");
			}
			this.checkUser(authToken, user);
			return new SimpleAuthenticationInfo(user, authToken.getCredentials(), getName());
		} else if (token instanceof UsernamePasswordToken) {
			UsernamePasswordToken upt = (UsernamePasswordToken) token;
			UserNamePasswordToken convert_upt = new UserNamePasswordToken(upt.getUsername(), upt.getPassword());
			IAutumnUser user = this.getCredentialsService().loadUserByToken(convert_upt);
			if (user == null) {
				throw new AutumnAccountCredentialsException("无效的用户认证。");
			}
			this.checkUser(convert_upt, user);
			return new SimpleAuthenticationInfo(user, convert_upt.getCredentials(), getName());
		}
		logger.error("不支持的认证类型:" + token.getClass().getName());
		throw new AutumnAuthenticationException("不支持登录方式。");
	}

	/**
	 * 
	 * @param user
	 */
	private void checkUser(AutumnAuthenticationToken token, IAutumnUser user) {
		if (user.getStatus() == null) {
			logger.error("用户名:" + user.getUserName() + " 的状态无效,无法登录。");
			throw new AutumnAccountStatusException("账户状态无效，不能登录。");
		}
		switch (user.getStatus()) {
		case UserStatusConstants.LOCKING:
			throw new AutumnAccountStatusException("账户已锁定，不能登录。");
		case UserStatusConstants.NOT_ACTIVATE:
			throw new AutumnAccountStatusException("账户未激活，不能登录。");
		case UserStatusConstants.EXPIRED:
			throw new AutumnAccountStatusException("账户已过期，不能登录。");
		default:
			break;
		}
	}

	@Override
	public boolean supports(AuthenticationToken token) {
		if (token == null) {
			return false;
		}
		return AutumnAuthenticationToken.class.isAssignableFrom(token.getClass());
	}

}
